package com.tedu.api.io;

import org.junit.Test;

import java.io.*;

/**
 * 标准IO流----目的：数据传输  输出文本、图片
 * java定义一套标准流-->数据传输-->
 * 标准流规则①：方向划分  输入流和输出流
 *         输入流：读入-->文件--->相当于程序--->文件往程序走
 *         InputStream(抽象类：定义所有读的写法)
 *         输出流：写出-->文件--->相当于程序--->程序写出
 *         OutputStream(抽象类：定义所有写的方法)【学习：子实现类】
 *         ②：功能划分
 *         低级流【节点流】：是建立在程序与数据源之间的“管道”
 *         功能：负责搬运的数据流，输入流于输出流都有自己的低级流
 *         特点：一个字节一个字节读或者写的方法
 *         FileOutputStream  低级流继承InputStream---文件输出流：写
 *         FileInputStream   低级流继承OutputStream--文件输入流：读
 *         高级流【处理流】：不能直接创建对象，不能独立存在
 *                   功能：专门处理低级流以及其他高级流的流
 *                   特点：搬运数据的时，实现具体的功能，效率提高流
 *         --总结：输入流和输出流，具备功能：低级流与高级流，
 *         实际使用：明确使用具体流，每个流都有自己功能
 */
public class IOAPI {


    /**
     * 文件输入流
     * 输入流    低级流---
     * 标准流  方向:     功能：     文件输出流：FileOutputStream
     * 输出流    高级流
     * 需求：写出一个文件 fos.txt
     * new FileOutputStream("路径+文件全称")
     * new FileOutputStream("路径+文件全称",boolean append)
     * 写出文件的同时实现追加效果，第二个参数：true   追加
     * false  默认不追加
     * new FileOutputStream(File file,boolean append);
     * 写出文件，采用File传入路径+全称
     */


    @Test
    public void testFOS() throws IOException {
       /* RandomAccessFile raf=
                new RandomAccessFile("fos.txt","r");*/
        //低级流---文件输出流对象----从程序中写出“文件：数据”
        FileOutputStream fos =
                new FileOutputStream("fos.txt");
        //需求：fos.txt 增加一行文本，每一次运行实现追加效果
        String say = "独one无two";
        //字符串由字符数组构成--数组的功能--getBytes()转换为字节数组
        //输出流--写功能：write(byte[] b)  写出字节数组
        fos.write(say.getBytes("UTF8"));
        //必须关闭流--目的：节省内存开销
        fos.close();
    }

    /**
     * 文件输入流：读入操作
     * FileInputStream 文件输入流
     * read() 返回一个读取一个字节--效率低
     * read(字节数组byte[]b)
     * 返回一个”指定字节数组：空间大小“的读取---效率高
     * 需求：读入fos.txt文件内容
     */
    @Test
    public void testFIS() throws IOException {
        //创建文件输入流---读入：fos.txt
        FileInputStream fis = new FileInputStream("fos.txt");
        //读入效率高：创建字节数组--指定空间为：10KB
        byte[] data = new byte[1024*10];
        //读入操作：read(字节数组) |  以10KB读入数据
        int len = fis.read(data);
        //写出：文本---字符串--针对流操作，提供构造器
        //                    文件按照”指定字节数组空间“写入程序中
        //                    从0开始写入程序，写入到-1结束
        //                    len:十进制转换为二进制，写入，不等-1，一直写入
        //一次性将给定数据按照字节数组指定空间的大小，写出成字符串
        String str = new String(data, 0, len);
        System.out.println("打印Fos.txt文件：" + str);

    }

    @Test
    public void testCV() throws IOException {
        //1.从”复制文件.mp4“粘贴 操作---读入
        FileInputStream fis = new FileInputStream("复制文件.mp4");
        //2.创建新文件”新文件.mp4“ 粘贴 操作---写出
        FileOutputStream fos = new FileOutputStream("新文件.mp4");
        //3.保存每次读取的数据【字节量--lin】
        int len = -1;
        //4.一直从”复制文件.mp4“进行读入操作，不等于-1    一直读
        //(len=fis.read())!=-1
        while ((len = fis.read()) != -1) {//true
            //4.1同时 写出“新文件.mp4”
            fos.write(len);

        }

        //5.关闭流                   ---测：效率低---正常播放
        fis.close();
        fis.close();
    }

    /**
     * 需求：利用标准流实现视频复制粘贴--效率低
     * 效率高--->空间执行为：自定 100KB
     * 【高级流】BufferedInputStream  缓冲输入流--提升效率--缓冲区：【长度按照文件带下合理分配】
     * 【高级流】BufferedOutputStream  缓冲输出流--提升效率--缓冲区：【长度按照文件带下合理分配】
     * 高级流使用方法：①处理低级流，套在低级流上
     * 写法：new 高级流(传入低级流的引用)
     * ②直接使用高级流的方法
     * ③高级流不能直接创建【不能独立存在】
     */
    @Test
    public void testCVS() throws IOException {
        //创建低级流：读入“复制文件”
        FileInputStream fis =
                new FileInputStream("复制文件.mp4");
        //1.创建高级流：套在低级流上【自带缓冲区：字节数组】
        BufferedInputStream bis = new BufferedInputStream(fis);

        //2.创建低级流：写出“高效视频.mp4”
        FileOutputStream fos =
                new FileOutputStream("高效视频.mp4");
        //2.创建高级流：套在低级流上【自带缓冲区：字节数组】
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        //3.保存数据
        int len = -1;
        //4.高级流--低级流方法一致---read()
        //一直从“复制视频.mp4”读取数据，不等于-1，一直读
        //(len=bis.read())!=-1
        long start=System.currentTimeMillis();//系统时间毫秒数
        while ((len = bis.read()) != -1) {
            bos.write(len);
        }
        long end=System.currentTimeMillis();
        System.out.println("缓冲流【自带缓冲】："+(end-start)+"毫秒数");
        //关闭流---  高级流与低级流：都关--->高级流间接性关闭低级流
        bis.close(); //高级流--文件输入流
        bos.close(); //高级流--缓冲输出流

    }
/**
 * 高级流---缓冲流【内嵌缓冲区】
 * BufferedOutStream   缓冲输出流
 *
 * 需求：通过缓冲输出流实现从程序写出文件：bos.txt,写出内容
 */
@Test
    public void testBOS() throws IOException {
    //1.创建低级流-->bos.txt
    FileOutputStream fos=new FileOutputStream("bos.txt");
    //2.创建一个高级流-->缓冲区：字节数组--合理
    BufferedOutputStream bos=new BufferedOutputStream(fos);
    //3.写出文本内容
    String str="喂，我是皮皮~~你找简少干啥呀";
    //4.写出到bos.txt文件中:字符串转成字节数组--写出
    bos.write(str.getBytes());
    //5.将缓冲区数据一次性写出 flush()  【立即写出】
    //bos.flush();
    //A    B   你好    你认识我吗   干哈呢  ？？
    bos.close();  //关闭流---一定把缓冲区数据全部写出
}


/**
 * 标准IO---成对【低级流+高级流】集合异常--数据传输--成功【异常需要捕获】
 * 需求：重构  testBOS()  单元测试
 */
@Test
    public void testBOSIO(){
    //1.置空流---提升所有流的作用域：增加适用范围
    FileOutputStream fos=null;  //低级流：搬运数据
    BufferedOutputStream bos=null;//高级流：缓冲输出流
    //2.捕获流的异常并且做出处理
    try {
        fos=new FileOutputStream("bos.txt");//低级流
        bos=new BufferedOutputStream(fos);//高级流
        bos.write("世一锋洁世一".getBytes());
        bos.flush();
    }catch(FileNotFoundException e){//IO流”小“异常，
        e.printStackTrace();
    } catch (IOException e) {//IO流”中“异常：小异常父类
    }catch(Exception e){//”大“异常，  Exception
        e.printStackTrace();
    } finally {//一定执行代码块
        //3.关闭流---高级流---释放资源
        //判断：高级流是否 1.高级流不为null，关闭
        try {
            if(bos!=null)
                bos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
//***finally与final的区别【使用】
    //final【最终】修饰类 不可改变类 | 修饰属性 不可改变值【常量】 | 修饰方法 方法不可以重写，可以重载
    //finally处理异常快：关闭流


}

